package org.naxx.security.testng.parsing;

import java.io.InputStream;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;

import org.apache.log4j.Logger;
import org.naxx.security.parser.validation.SchemaValidator;
import org.naxx.security.test.unit.dev.parser.AbstractSingleFileParsingTestCase;
import org.naxx.security.testng.SpringContextAware;
import org.naxx.security.util.FileSystemUtil;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

public abstract class AbstractSingleXmlFileParsingAware extends SpringContextAware {

	private static final Logger logger = Logger.getLogger(AbstractSingleFileParsingTestCase.class);

	protected InputStream in;
	protected XMLEventReader reader;
	
	/**
	 * Name of the file on classpath this test case should 
	 * load and parse.
	 */
	protected abstract String getXmlFileClasspathLocation();
	
	/**
	 * Override if you want to bypass XML schema validation.
	 * Not recommended. Default is <code>true</code>.
	 */
	protected boolean shouldValidateAgainstXacmlSchema() {
		return true;
	}

	@BeforeClass
	public void setUp() throws Exception {
		super.setUp();
		if(this.shouldValidateAgainstXacmlSchema()) {
			this.validateAgainstSchema();
		}
		this.in = this.getFromClasspath(this.getXmlFileClasspathLocation());
		this.reader = XMLInputFactory.newInstance().createXMLEventReader(this.in);
		
	}
	
	@AfterClass(alwaysRun=true)
	public void tearDown() throws Exception {
		FileSystemUtil.release(this.reader);
		FileSystemUtil.close(this.in);
		super.tearDown();
	}
	
	// PERFORMANCE add support to read file once but create from it
	// two in memory streams for performance reasons
	private void validateAgainstSchema() throws Exception {
		InputStream in = null;
		try {
			in = this.getFromClasspath(getXmlFileClasspathLocation());
			this.repository.getService(SchemaValidator.class).validate(in);
		} catch (Exception e) {
			String errorMessage = "File on classpath '" + this.getXmlFileClasspathLocation() + "' is not " +
					"valid according to XACML schema";
			logger.error(errorMessage, e);
			throw new IllegalArgumentException(errorMessage);
		} finally {
			FileSystemUtil.close(in);
		}
	}
	
	protected InputStream getFromClasspath(String resourceName) {
		return Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
	}
}
